/*
 * Copyright 2007 MBARI
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*
MonitoringVCR.java
 *
Created on December 1, 2005, 4:17 PM
 *
To change this template, choose Tools | Template Manager
and open the template in the editor.
 */

package org.mbari.vcr;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.mbari.movie.Timecode;

/**
 * This class is a replacement fo the SonyVCRProxy. It is greatly simplified and
 * does much more. It monitors timecode as well as state automatically. In record
 * mode it also writes timecode to the userbits on the tape.
 *
 * TODO 20051202 brian: This class needs to be tested.
 * @author brian
 */
public class MonitoringVCR implements IVCR {

    /**
     *     @uml.property  name="stateObservers"
     *     @uml.associationEnd  multiplicity="(0 -1)" elementType="org.mbari.vcr.StateObserver"
     */
    private final Set stateObservers = new HashSet();

    /**
     *     @uml.property  name="vcr"
     *     @uml.associationEnd  multiplicity="(1 1)"
     */
    private IVCR vcr;

    /**
     * Creates a new instance of StateAwareVCR
     */
    public MonitoringVCR() {
        setVcr(new VCRAdapter());
    }

    /**
     * Constructs ...
     *
     *
     * @param vcr
     */
    public MonitoringVCR(IVCR vcr) {
        if (vcr == null) {
            throw new IllegalArgumentException("VCR can not be null");
        }

        setVcr(vcr);
    }

    /**
     * Method description
     *
     *
     * @param stateObserver
     */
    public void addStateObserver(StateObserver stateObserver) {
        IVCRState vcrState = getVcrState();
        if (!stateObservers.contains(stateObserver)) {
            stateObservers.add(stateObserver);
            vcrState.addObserver(stateObserver);
        }
    }

    /**
     * Method description
     *
     */
    public void deviceTypeRequest() {
        vcr.deviceTypeRequest();
    }

    /**
     * Method description
     *
     */
    public void disconnect() {

        // Remove observers from existing VCR object
        synchronized (stateObservers) {
            IVCRState vcrState = getVcrState();
            for (Iterator i = stateObservers.iterator(); i.hasNext(); ) {
                StateObserver stateObserver = (StateObserver) i.next();
                vcrState.removeObserver(stateObserver);
                stateObserver.stopTimer();
            }
        }

        vcr.disconnect();
    }

    /** Eject the tape from the VTR */
    public void eject() {
        vcr.stop();
        vcr.releaseTape();
        vcr.eject();
    }

    /**
     * Method description
     *
     */
    public void fastForward() {
        vcr.fastForward();
    }

    /**
     * Method description
     *
     */
    public void pause() {
        vcr.pause();
    }

    /**
     * Method description
     *
     */
    public void play() {
        vcr.play();
    }

    /**
     * Method description
     *
     *
     * @param timecode
     */
    public void presetTimecode(byte[] timecode) {
        vcr.presetTimecode(timecode);
    }

    /**
     * Method description
     *
     *
     * @param userbits
     */
    public void presetUserbits(byte[] userbits) {
        vcr.presetUserbits(userbits);
    }

    /**
     * Method description
     *
     */
    public void record() {
        vcr.record();
    }

    /**
     * Method description
     *
     */
    public void releaseTape() {
        vcr.releaseTape();
    }

    /**
     * Method description
     *
     */
    public void removeAllObservers() {
        vcr.removeAllObservers();
    }

    /**
     * Method description
     *
     */
    public void requestLTimeCode() {
        vcr.requestLTimeCode();
    }

    /**
     * Method description
     *
     */
    public void requestLUserbits() {
        vcr.requestLUserbits();
    }

    /**
     * Method description
     *
     */
    public void requestLocalDisable() {
        vcr.requestLocalDisable();
    }

    /**
     * Method description
     *
     */
    public void requestLocalEnable() {
        vcr.requestLocalEnable();
    }

    /**
     * Method description
     *
     */
    public void requestStatus() {
        vcr.requestStatus();
    }

    /**
     * Method description
     *
     */
    public void requestTimeCode() {
        vcr.requestTimeCode();
    }

    /**
     * Method description
     *
     */
    public void requestVTimeCode() {
        vcr.requestVTimeCode();
    }

    /**
     * Method description
     *
     */
    public void requestVUserbits() {
        vcr.requestVUserbits();
    }

    /**
     * Method description
     *
     */
    public void rewind() {
        vcr.rewind();
    }

    /**
     * Method description
     *
     *
     * @param timecode
     */
    public void seekTimecode(byte[] timecode) {
        vcr.seekTimecode(timecode);
    }

    /**
     * Method description
     *
     *
     * @param timecode
     */
    public void seekTimecode(int timecode) {
        vcr.seekTimecode(timecode);
    }
    
    

    /**
     * Method description
     *
     *
     * @param speed
     */
    public void shuttleForward(int speed) {
        vcr.shuttleForward(speed);
    }

    /**
     * Method description
     *
     *
     * @param speed
     */
    public void shuttleReverse(int speed) {
        vcr.shuttleReverse(speed);
    }

    /**
     * Method description
     *
     */
    public void stop() {
        vcr.stop();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getConnectionName() {
        return vcr.getConnectionName();
    }

    /**
     *     @return  the vcr
     *     @uml.property  name="vcr"
     */
    public IVCR getVcr() {
        return vcr;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IVCRError getVcrError() {
        return vcr.getVcrError();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IVCRReply getVcrReply() {
        return vcr.getVcrReply();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IVCRState getVcrState() {
        return vcr.getVcrState();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IVCRTimecode getVcrTimecode() {
        return vcr.getVcrTimecode();
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IVCRUserbits getVcrUserbits() {
        return vcr.getVcrUserbits();
    }

    /**
     *     @param vcr  the vcr to set
     *     @uml.property  name="vcr"
     */
    public void setVcr(IVCR vcr) {

        if (vcr == null) {
            throw new IllegalArgumentException("You attempted to set the VCR " +
                                               "Property to null. This is not allowed!");
        }

        // Remove observers from existing VCR object
        if (this.vcr != null) {
            IVCRState vcrState = getVcrState();
            for (Iterator i = stateObservers.iterator(); i.hasNext(); ) {
                StateObserver stateObserver = (StateObserver) i.next();
                vcrState.removeObserver(stateObserver);
                stateObserver.stopTimer();
            }
        }

        // Add observers to new VCR object
        this.vcr = vcr;
        IVCRState vcrState = getVcrState();
        for (Iterator i = stateObservers.iterator(); i.hasNext(); ) {
            StateObserver stateObserver = (StateObserver) i.next();
            vcrState.removeObserver(stateObserver);
        }

    }

    public void seekTimecode(Timecode timecode) {
        vcr.seekTimecode(timecode);
    }
}
